package com.code.service.initializer;

import com.alibaba.fastjson2.JSON;
import com.code.service.config.ServiceConfig;
import com.code.service.message.HeartBeatMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@Component
@Slf4j
public class ActivityDetectionInitializer implements CommandLineRunner {
    @Autowired
    private ServiceConfig serviceConfig;
    private static final String MAGIC_NUM = "010101";
    private SocketChannel socketChannel = null;
    private ScheduledExecutorService scheduledExecutorService = null;

    @Override
    public void run(String... args) throws Exception {
        ByteBuffer byteBuffer = ByteBuffer.allocate(200);
        try {
            log.info("启动状态检测任务....");
            String activeIP = serviceConfig.getServerIp();
            String serviceName = serviceConfig.getServiceName();
            Integer maxReconnectTime = 3;
            boolean connect = connect(activeIP, null, serviceName);
            if (!connect) {
                log.info("minitor没有启动...");
            }
            log.info("连接到monitor..");

            ThreadFactory threadFactory = new ThreadFactory() {
                @Override
                public Thread newThread(Runnable r) {
                    Thread thread = new Thread(r);
                    thread.setDaemon(false);
                    thread.setName("hearbeat_thread");
                    return thread;
                }
            };

            AtomicInteger retry = new AtomicInteger(0);
            AtomicBoolean retryResult = new AtomicBoolean(true);
            scheduledExecutorService = new ScheduledThreadPoolExecutor(1, threadFactory);
            scheduledExecutorService.scheduleAtFixedRate(() -> {
                try {
                    if (retryResult.get()) {
                        log.info("发送心跳消息..");
                        buildHeartBeatMessage(byteBuffer, activeIP, null, "自动化测试程序");
                        socketChannel.write(byteBuffer);
                    } else {
                        if (retry.incrementAndGet() > maxReconnectTime) {
                            log.error("连接断开，关闭定时任务");
                            scheduledExecutorService.shutdown();
                        } else {
                            log.info("连接断开，尝试重新连接.....");
                            boolean reconnect = connect(activeIP, null, serviceName);
                            retryResult.set(reconnect);
                            if (!reconnect) {
                                log.info("第{}次连接失败", retry.get());
                            } else {
                                log.info("第{}次连接成功", retry.get());
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    retryResult.set(false);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("{}", e);
                }
            }, 1, 10, TimeUnit.SECONDS);
        } catch (Exception e) {
            System.out.println(e.getClass());
            e.printStackTrace();
            log.error("{}", e);
        }

//        TimeUnit.DAYS.sleep(1);
    }

    private boolean connect(String activeIp, Integer port, String serviceName) {
        try {
            ByteBuffer byteBuffer = ByteBuffer.allocate(200);
            socketChannel = SocketChannel.open(new InetSocketAddress(serviceConfig.getManagerHost(), serviceConfig.getManagerPort()));
            socketChannel.configureBlocking(false);

            buildHeartBeatMessage(byteBuffer, activeIp, port, serviceName);
            socketChannel.write(byteBuffer);

            return true;
        } catch (Exception e) {
            log.error("{}", e);
        }
        return false;
    }

    @PreDestroy
    public void destory() {
        try {
            socketChannel.close();
            scheduledExecutorService.shutdown();

            while (socketChannel.isOpen()) {
                socketChannel.close();
            }
            while (!scheduledExecutorService.isShutdown()) {
                scheduledExecutorService.shutdownNow();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void buildHeartBeatMessage(ByteBuffer byteBuffer, String ip, Integer port, String serviceName) {
        byteBuffer.clear();
        // 添加自定义消息魔数和序列化方式
        byteBuffer.put(MAGIC_NUM.getBytes());
        byteBuffer.put((byte) 2);
        byteBuffer.put((byte) 1);

        HeartBeatMessage heartBeatMessage = new HeartBeatMessage();
        heartBeatMessage.setIp(ip);
        heartBeatMessage.setPort(port);
        heartBeatMessage.setServiceName(serviceName);
        heartBeatMessage.setOperationSystem(System.getProperty("os.name"));

        byte[] messages = JSON.toJSONString(heartBeatMessage).getBytes(Charset.forName("UTF-8"));
        byteBuffer.putInt(messages.length);
        byteBuffer.put(messages);
        byteBuffer.flip();
    }
}

